package org.finesys.common.netty.websocket.support;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;

import javax.net.ssl.SSLException;

import org.finesys.common.netty.websocket.annotation.EnableWebSocket;
import org.finesys.common.netty.websocket.annotation.WebSocketEndpoint;
import org.finesys.common.netty.websocket.exception.WebSocketException;
import org.finesys.common.netty.websocket.service.impl.WebSocketSendServiceImpl;
import org.finesys.common.netty.websocket.service.impl.WebSocketStompSendServiceImpl;
import org.finesys.common.netty.websocket.stomp.support.StompWebSocketEndpointEventServer;
import org.finesys.common.netty.websocket.stomp.support.StompWebSocketEndpointMethodMapping;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.support.AbstractBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ResourceLoader;
import org.springframework.lang.NonNull;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;

public class WebSocketEndpointExporter extends ApplicationObjectSupport implements SmartInitializingSingleton, BeanFactoryAware, ResourceLoaderAware {
    /**
     * Bean工厂
     */
    private AbstractBeanFactory beanFactory;
    /**
     * 资源路径
     */
    private ResourceLoader resourceLoader;

    /**
     * 服务Map
     */
    private final Map<InetSocketAddress, WebSocketServer> addressWebSocketServerMap = new HashMap<>();

    @Value("${webSocket.logLevel:info}")
    private String logLevel;

    @Override
    public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
        if (!(beanFactory instanceof AbstractBeanFactory)) {
            throw new IllegalArgumentException("AutowiredAnnotationBeanPostProcessor requires a AbstractBeanFactory: " + beanFactory);
        }
        this.beanFactory = (AbstractBeanFactory) beanFactory;
    }

    @Override
    public void afterSingletonsInstantiated() {
        registerEndPoints();
    }


    @Override
    public void setResourceLoader(@NonNull ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    /**
     * 注册WebSocket端点。
     * <p>
     * 此方法首先获取应用程序上下文，然后调用scanPackage方法来扫描包含WebSocket端点的包。
     * 接着，它使用WebSocketEndpoint注解来查找所有WebSocket端点bean的名称。
     * 对于每个找到的端点bean名称，它获取bean的类型（Class对象），并将这些类型添加到一个LinkedHashSet集合中，
     * 以确保端点类型的唯一性。
     * <p>
     * 然后，对于集合中的每个端点类型，它检查类名是否包含CGLIB动态代理的标记。
     * 如果是动态代理类，则注册其超类作为端点；否则，直接注册该类作为端点。
     * <p>
     * 最后，调用init方法来初始化所有已注册的端点。
     */
    private void registerEndPoints() {
        ApplicationContext context = getApplicationContext();
        if(context==null){
            throw new RuntimeException("注册websocket失败，未获取到ApplicationContext！");
        }
        scanPackage(context);
        String[] endPointBeanNames = context.getBeanNamesForAnnotation(WebSocketEndpoint.class);
        Set<Class<?>> endPointClasses = new LinkedHashSet<>();
        for (String beanName : endPointBeanNames) {
            endPointClasses.add(context.getType(beanName));
        }
        for (Class<?> endPointClass : endPointClasses) {
            String name = endPointClass.getName();
            //判断是否动态代理
            if (name.contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
                registerEndPoint(endPointClass.getSuperclass());
            } else {
                registerEndPoint(endPointClass);
            }
        }
        init();
    }


    /**
     * 扫描包以查找WebSocket端点。
     * <p>
     * 该方法首先尝试从具有@EnableWebSocket注解的bean中获取扫描基础包。
     * 如果找不到这样的bean或没有指定扫描基础包，则尝试从具有@SpringBootApplication注解的bean中获取扫描基础包。
     * 如果仍然无法获取到扫描包，则使用当前Spring Boot应用程序的包名作为扫描包。
     * <p>
     * 使用获取到的扫描包，创建一个EndpointClassPathScanner实例来扫描WebSocket端点。
     * 如果资源加载器（resourceLoader）不为空，则将其设置给EndpointClassPathScanner实例。
     * 最后，调用EndpointClassPathScanner的doScan方法来执行扫描操作。
     *
     * @param context Spring应用程序上下文，用于获取bean和注解信息
     */
    private void scanPackage(ApplicationContext context) {
        String[] basePackages = null;
        //获取EnableWebSocket的扫描路径
        String[] enableWebSocketBeanNames = context.getBeanNamesForAnnotation(EnableWebSocket.class);
        for (String enableName : enableWebSocketBeanNames) {
            Object enableWebSocketBean = context.getBean(enableName);
            EnableWebSocket enableWebSocket = AnnotationUtils.findAnnotation(enableWebSocketBean.getClass(), EnableWebSocket.class);
            if(enableWebSocket!=null){
                if (enableWebSocket.scanBasePackages().length != 0) {
                    basePackages = enableWebSocket.scanBasePackages();
                    break;
                }
            }
        }
        //获取不到扫描包
        if (basePackages == null) {
            //获取SpringBootApplication的扫描路径
            String[] springbootApplicationBeanNames = context.getBeanNamesForAnnotation(EnableWebSocket.class);
            Object springBootApplicationBean = context.getBean(springbootApplicationBeanNames[0]);
            SpringBootApplication springBootApplication = AnnotationUtils.findAnnotation(springBootApplicationBean.getClass(), SpringBootApplication.class);
            if(springBootApplication==null){
                throw new RuntimeException("获取SpringBootApplication失败");
            }
            if (springBootApplication.scanBasePackages().length != 0) {
                basePackages = springBootApplication.scanBasePackages();
            } else {
                // Scan current application path
                String packageName = ClassUtils.getPackageName(springBootApplication.getClass().getName());
                basePackages = new String[1];
                basePackages[0] = packageName;
            }
        }

        EndpointClassPathScanner endpointClassPathScanner = new EndpointClassPathScanner((BeanDefinitionRegistry) context, false);
        if (resourceLoader != null) {
            endpointClassPathScanner.setResourceLoader(resourceLoader);
        }
        //scan
        endpointClassPathScanner.doScan(basePackages);
    }

    public WebSocketEndpointExporter() {
        super();
    }

    /**
     * 注册WebSocket端点。
     *
     * @param endPointClass 需要注册的WebSocket端点类
     * @throws IllegalArgumentException 如果指定类上没有WebSocketEndpoint注解，则抛出此异常
     * @throws RuntimeException         如果在注册过程中发生错误，则抛出此异常
     */
    private void registerEndPoint(Class<?> endPointClass) {
        // 从指定类上查找合并后的WebSocketEndpoint注解
        WebSocketEndpoint webSocketEndpoint = AnnotatedElementUtils.findMergedAnnotation(endPointClass, WebSocketEndpoint.class);
        if (webSocketEndpoint == null) {
            // 如果未找到WebSocketEndpoint注解，则抛出异常
            throw new IllegalArgumentException("missingAnnotation WebSocketEndpoint");
        }
        // 构建WebSocket配置
        WebSocketEndpointConfig webSocketEndpointConfig = buildWebSocketConfig(webSocketEndpoint);
        try {
            if ("wss".equals(webSocketEndpointConfig.getProtocol())) {
                stompWebsocketServerInit(endPointClass, webSocketEndpoint, webSocketEndpointConfig);
            } else {
                websocketServerInit(endPointClass, webSocketEndpoint, webSocketEndpointConfig);
            }
        } catch (SSLException e) {
            throw new RuntimeException(e);
        }
    }

    private void websocketServerInit(Class<?> endPointClass, WebSocketEndpoint webSocketEndpoint, WebSocketEndpointConfig webSocketEndpointConfig) throws SSLException {
        // 获取应用上下文
        ApplicationContext context = getApplicationContext();
        // 初始化WebSocket端点方法映射
        WebSocketEndpointMethodMapping webSocketEndpointMethodMapping;
        try {
            // 创建WebSocket端点方法映射实例
            webSocketEndpointMethodMapping = new WebSocketEndpointMethodMapping(endPointClass, context, beanFactory);
        } catch (WebSocketException e) {
            // 如果创建WebSocket端点方法映射时发生异常，则抛出运行时异常
            throw new RuntimeException("Failed to register ServerEndpoint:" + e);
        }
        // 创建InetSocketAddress实例
        InetSocketAddress inetSocketAddress = new InetSocketAddress(webSocketEndpointConfig.getHost(), Integer.parseInt(webSocketEndpointConfig.getPort()));
        // 解析WebSocketEndpoint注解中的path属性值
        String path = resolveAnnotationValue(webSocketEndpoint.path(), String.class, "path");
        // 从映射中获取WebSocketServer实例
        WebSocketServer webSocketServer = addressWebSocketServerMap.get(inetSocketAddress);
        if (webSocketServer == null) {
            // 如果WebSocketServer实例不存在，则创建WebSocketEndpointEventServer实例
            WebSocketEndpointEventServer webSocketEndpointExporter = new WebSocketEndpointEventServer(webSocketEndpointMethodMapping, webSocketEndpointConfig, path);
            // 创建WebSocketServer实例
            webSocketServer = new WebSocketServer(webSocketEndpointExporter, null, webSocketEndpointConfig);
            // 将新创建的WebSocketServer实例放入映射中
            addressWebSocketServerMap.put(inetSocketAddress, webSocketServer);
        } else {
            // 如果WebSocketServer实例已存在，则向其添加路径与方法映射
            webSocketServer.getWebSocketEndpointEventServer().addPathMethodMapping(path, webSocketEndpointMethodMapping);
        }
    }

    private void stompWebsocketServerInit(Class<?> endPointClass, WebSocketEndpoint webSocketEndpoint, WebSocketEndpointConfig webSocketEndpointConfig) throws SSLException {
        // 获取应用上下文
        ApplicationContext context = getApplicationContext();
        // 初始化WebSocket端点方法映射
        StompWebSocketEndpointMethodMapping stompWebSocketEndpointMethodMapping;
        try {
            // 创建WebSocket端点方法映射实例
            stompWebSocketEndpointMethodMapping = new StompWebSocketEndpointMethodMapping(endPointClass, context, beanFactory);
        } catch (WebSocketException e) {
            // 如果创建WebSocket端点方法映射时发生异常，则抛出运行时异常
            throw new RuntimeException("Failed to register ServerEndpoint:" + e);
        }
        // 创建InetSocketAddress实例
        InetSocketAddress inetSocketAddress = new InetSocketAddress(webSocketEndpointConfig.getHost(), Integer.parseInt(webSocketEndpointConfig.getPort()));
        // 解析WebSocketEndpoint注解中的path属性值
        String path = resolveAnnotationValue(webSocketEndpoint.path(), String.class, "path");
        // 从映射中获取WebSocketServer实例
        WebSocketServer webSocketServer = addressWebSocketServerMap.get(inetSocketAddress);
        if (webSocketServer == null) {
            // 如果WebSocketServer实例不存在，则创建WebSocketEndpointEventServer实例
            StompWebSocketEndpointEventServer stompWebSocketEndpointExporter = new StompWebSocketEndpointEventServer(stompWebSocketEndpointMethodMapping, webSocketEndpointConfig, path);
            // 创建WebSocketServer实例
            webSocketServer = new WebSocketServer(null, stompWebSocketEndpointExporter, webSocketEndpointConfig);
            // 将新创建的WebSocketServer实例放入映射中
            addressWebSocketServerMap.put(inetSocketAddress, webSocketServer);
            //初始化bean对象
            if (context != null) {
                context.getAutowireCapableBeanFactory().initializeBean(new WebSocketStompSendServiceImpl(), "webSocketSendService");
            }

        } else {
            // 如果WebSocketServer实例已存在，则向其添加路径与方法映射
            webSocketServer.getStompWebSocketEndpointEventServer().addPathMethodMapping(path, stompWebSocketEndpointMethodMapping);
            //初始化bean对象
            if (context != null) {
                context.getAutowireCapableBeanFactory().initializeBean(new WebSocketSendServiceImpl(), "webSocketSendService");
            }
        }
    }

    /**
     * 根据WebSocketEndpoint注解构建WebSocket配置对象。
     *
     * @param annotation WebSocketEndpoint注解对象
     * @return 构建好的WebSocketEndpointConfig对象
     */
    //创建配置类
    private WebSocketEndpointConfig buildWebSocketConfig(WebSocketEndpoint annotation) {
        // 解析注解中的host属性
        String host = resolveAnnotationValue(annotation.host(), String.class, "host");
        // 解析注解中的port属性
        String port = resolveAnnotationValue(annotation.port(), String.class, "port");
        // 解析注解中的path属性
        String path = resolveAnnotationValue(annotation.path(), String.class, "path");
        // 解析注解中的bossLoopGroupThreads属性
        int bossLoopGroupThreads = resolveAnnotationValue(annotation.bossLoopGroupThreads(), Integer.class,
                "bossLoopGroupThreads");
        // 解析注解中的workerLoopGroupThreads属性
        int workerLoopGroupThreads = resolveAnnotationValue(annotation.workerLoopGroupThreads(), Integer.class,
                "workerLoopGroupThreads");
        // 解析注解中的useCompressionHandler属性
        boolean useCompressionHandler = resolveAnnotationValue(annotation.useCompressionHandler(), Boolean.class,
                "useCompressionHandler");

        // 解析注解中的optionConnectTimeoutMillis属性
        int optionConnectTimeoutMillis = resolveAnnotationValue(annotation.optionConnectTimeoutMillis(), Integer.class,
                "optionConnectTimeoutMillis");
        // 解析注解中的optionSoBacklog属性
        int optionSoBacklog = resolveAnnotationValue(annotation.optionSoBacklog(), Integer.class, "optionSoBacklog");

        // 解析注解中的childOptionWriteSpinCount属性
        int childOptionWriteSpinCount = resolveAnnotationValue(annotation.childOptionWriteSpinCount(), Integer.class,
                "childOptionWriteSpinCount");
        // 解析注解中的childOptionWriteBufferHighWaterMark属性
        int childOptionWriteBufferHighWaterMark = resolveAnnotationValue(
                annotation.childOptionWriteBufferHighWaterMark(), Integer.class, "childOptionWriteBufferHighWaterMark");
        // 解析注解中的childOptionWriteBufferLowWaterMark属性
        int childOptionWriteBufferLowWaterMark = resolveAnnotationValue(annotation.childOptionWriteBufferLowWaterMark(),
                Integer.class, "childOptionWriteBufferLowWaterMark");
        // 解析注解中的childOptionSoRcvbuf属性
        int childOptionSoRcvbuf = resolveAnnotationValue(annotation.childOptionSoRcvbuf(), Integer.class,
                "childOptionSoRcvbuf");
        // 解析注解中的childOptionSoSndbuf属性
        int childOptionSoSndbuf = resolveAnnotationValue(annotation.childOptionSoSndbuf(), Integer.class,
                "childOptionSoSndbuf");
        // 解析注解中的childOptionTcpNodelay属性
        boolean childOptionTcpNodelay = resolveAnnotationValue(annotation.childOptionTcpNodelay(), Boolean.class,
                "childOptionTcpNodelay");
        // 解析注解中的childOptionSoKeepalive属性
        boolean childOptionSoKeepalive = resolveAnnotationValue(annotation.childOptionSoKeepalive(), Boolean.class,
                "childOptionSoKeepalive");
        // 解析注解中的childOptionSoLinger属性
        int childOptionSoLinger = resolveAnnotationValue(annotation.childOptionSoLinger(), Integer.class,
                "childOptionSoLinger");
        // 解析注解中的childOptionAllowHalfClosure属性
        boolean childOptionAllowHalfClosure = resolveAnnotationValue(annotation.childOptionAllowHalfClosure(),
                Boolean.class, "childOptionAllowHalfClosure");

        // 解析注解中的readerIdleTimeSeconds属性
        int readerIdleTimeSeconds = resolveAnnotationValue(annotation.readerIdleTimeSeconds(), Integer.class,
                "readerIdleTimeSeconds");
        // 解析注解中的writerIdleTimeSeconds属性
        int writerIdleTimeSeconds = resolveAnnotationValue(annotation.writerIdleTimeSeconds(), Integer.class,
                "writerIdleTimeSeconds");
        // 解析注解中的allIdleTimeSeconds属性
        int allIdleTimeSeconds = resolveAnnotationValue(annotation.allIdleTimeSeconds(), Integer.class,
                "allIdleTimeSeconds");

        // 解析注解中的maxFramePayloadLength属性
        int maxFramePayloadLength = resolveAnnotationValue(annotation.maxFramePayloadLength(), Integer.class,
                "maxFramePayloadLength");

        // 解析注解中的useEventExecutorGroup属性
        boolean useEventExecutorGroup = resolveAnnotationValue(annotation.useEventExecutorGroup(), Boolean.class,
                "useEventExecutorGroup");
        // 解析注解中的eventExecutorGroupThreads属性
        int eventExecutorGroupThreads = resolveAnnotationValue(annotation.eventExecutorGroupThreads(), Integer.class,
                "eventExecutorGroupThreads");

        // 解析注解中的sslKeyPassword属性
        String sslKeyPassword = resolveAnnotationValue(annotation.sslKeyPassword(), String.class, "sslKeyPassword");
        // 解析注解中的sslKeyStore属性
        String sslKeyStore = resolveAnnotationValue(annotation.sslKeyStore(), String.class, "sslKeyStore");
        // 解析注解中的sslKeyStorePassword属性
        String sslKeyStorePassword = resolveAnnotationValue(annotation.sslKeyStorePassword(), String.class,
                "sslKeyStorePassword");
        // 解析注解中的sslKeyStoreType属性
        String sslKeyStoreType = resolveAnnotationValue(annotation.sslKeyStoreType(), String.class, "sslKeyStoreType");
        // 解析注解中的sslTrustStore属性
        String sslTrustStore = resolveAnnotationValue(annotation.sslTrustStore(), String.class, "sslTrustStore");
        // 解析注解中的sslTrustStorePassword属性
        String sslTrustStorePassword = resolveAnnotationValue(annotation.sslTrustStorePassword(), String.class,
                "sslTrustStorePassword");
        // 解析注解中的sslTrustStoreType属性
        String sslTrustStoreType = resolveAnnotationValue(annotation.sslTrustStoreType(), String.class,
                "sslTrustStoreType");
        // 解析注解中的protocol属性
        String protocol = resolveAnnotationValue(annotation.protocol(), String.class,
                "protocol");
        // corsOrigins
        Boolean corsAllowCredentials = resolveAnnotationValue(annotation.corsAllowCredentials(), Boolean.class,
                "corsAllowCredentials");

        // 解析注解中的corsOrigins属性
        String[] corsOrigins = annotation.corsOrigins();
        if (!ObjectUtils.isEmpty(corsOrigins)) {
            for (int i = 0; i < corsOrigins.length; i++) {
                corsOrigins[i] = resolveAnnotationValue(corsOrigins[i], String.class, "corsOrigins");
            }
        }

        // 返回构建好的WebSocketEndpointConfig对象
        return new WebSocketEndpointConfig(host, port, path, bossLoopGroupThreads, workerLoopGroupThreads,
                useCompressionHandler, optionConnectTimeoutMillis, optionSoBacklog, childOptionWriteSpinCount,
                childOptionWriteBufferHighWaterMark, childOptionWriteBufferLowWaterMark, childOptionSoRcvbuf,
                childOptionSoSndbuf, childOptionTcpNodelay, childOptionSoKeepalive, childOptionSoLinger,
                childOptionAllowHalfClosure, readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds,
                maxFramePayloadLength, useEventExecutorGroup, eventExecutorGroupThreads, sslKeyPassword, sslKeyStore,
                sslKeyStorePassword, sslKeyStoreType, sslTrustStore, sslTrustStorePassword, sslTrustStoreType,
                corsOrigins, corsAllowCredentials, logLevel, protocol);
    }

    /**
     * 设置参数并支持SpEL表达式
     *
     * @param value        值
     * @param requiredType 参数类型
     * @param paramName    参数名
     * @param <T>          泛型类型
     * @return 泛型类型T
     * @throws IllegalArgumentException 当参数类型转换失败时抛出此异常
     */
    private <T> T resolveAnnotationValue(Object value, Class<T> requiredType, String paramName) {
        // 检查参数值是否为空
        if (ObjectUtils.isEmpty(value)) {
            return null;
        }

        // 如果参数值是字符串类型，则进行特殊处理
        if (value instanceof String) {
            // 使用Spring的BeanFactory解析SpEL表达式
            // spEL get configuration
            String strVal = beanFactory.resolveEmbeddedValue((String) value);

            // 获取BeanExpressionResolver以评估SpEL表达式
            BeanExpressionResolver beanExpressionResolver = beanFactory.getBeanExpressionResolver();

            // 如果BeanExpressionResolver不为空，则评估SpEL表达式
            if (beanExpressionResolver!=null) {
                value = beanExpressionResolver.evaluate(strVal, new BeanExpressionContext(beanFactory, null));
            } else {
                // 否则，直接使用解析后的字符串值
                value = strVal;
            }
        }

        try {
            // 获取类型转换器
            TypeConverter typeConverter = beanFactory.getTypeConverter();

            // 尝试将值转换为所需类型
            return typeConverter.convertIfNecessary(value, requiredType);
        } catch (TypeMismatchException e) {
            // 如果类型转换失败，抛出异常
            throw new IllegalArgumentException("Failed to convert value of parameter '" + paramName + "' to required type '" + requiredType.getName() + "'", e);
        }
    }


    /**
     * 初始化方法，用于启动所有的WebSocket服务器。
     * <p>
     * 遍历addressWebSocketServerMap映射中的每个条目，每个条目都包含一个InetSocketAddress和WebSocketServer的映射关系。
     * 对于映射中的每个WebSocketServer，执行以下操作：
     *
     * @throws RuntimeException 如果在初始化过程中遇到SSLException异常，则捕获该异常并抛出一个包含详细信息的RuntimeException
     */
    private void init() {
        // 遍历addressWebSocketServerMap映射中的每个条目
        for (Map.Entry<InetSocketAddress, WebSocketServer> entry : addressWebSocketServerMap.entrySet()) {
            // 获取当前条目的WebSocketServer对象
            WebSocketServer webSocketServer = entry.getValue();
            try {
                // 调用WebSocketServer的init方法进行初始化
                webSocketServer.init();
                // 获取WebSocketServer的WebSocketEndpointEventServer对象
                WebSocketEndpointEventServer webSocketEndpointEventServer = webSocketServer.getWebSocketEndpointEventServer();
                if(webSocketEndpointEventServer != null && webSocketEndpointEventServer.getPathMatchers() != null){
                    // 使用StringJoiner将WebSocketEndpointEventServer中所有路径匹配器的模式拼接成一个以逗号分隔的字符串
                    StringJoiner stringJoiner = new StringJoiner(",");
                    webSocketEndpointEventServer.getPathMatchers().forEach(wsPathMatcher -> stringJoiner.add("'" + wsPathMatcher.getPattern() + "'"));
                    // 使用日志记录器记录一条信息，表明Netty WebSocket已在指定端口启动，并列出了所有的WebSocket上下文路径
                    logger.info(String.format("Netty WebSocket started on port: %s with context path(s): %s .", webSocketEndpointEventServer.getPort(), stringJoiner.toString()));
                }else{
                    // 获取WebSocketServer的WebSocketEndpointEventServer对象
                    StompWebSocketEndpointEventServer stompWebSocketEndpointEventServer = webSocketServer.getStompWebSocketEndpointEventServer();
                    // 使用StringJoiner将WebSocketEndpointEventServer中所有路径匹配器的模式拼接成一个以逗号分隔的字符串
                    StringJoiner stringJoiner = new StringJoiner(",");
                    stompWebSocketEndpointEventServer.getPathMatchers().forEach(wsPathMatcher -> stringJoiner.add("'" + wsPathMatcher.getPattern() + "'"));
                    // 使用日志记录器记录一条信息，表明Netty WebSocket已在指定端口启动，并列出了所有的WebSocket上下文路径
                    logger.info(String.format("Netty WebSocket started on port: %s with context path(s): %s .", stompWebSocketEndpointEventServer.getPort(), stringJoiner.toString()));
                }
            } catch (SSLException e) {
                // 构造错误信息
                String message = String.format("websocket [%s] ssl create fail", entry.getKey());
                // 记录错误日志
                logger.error(message, e);
                // 抛出包含详细信息的WebSocketException异常
                throw new WebSocketException(message, e);
            }
        }
    }
}
